package client

import (
	"context"
	"fmt"

	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	pb "wowCoupon.com/rpcserver/customer/cer"
)

type CustomerRpcClient struct {
	addr       string
	conn       *grpc.ClientConn
	grpcClient pb.CerClient
}

// When generate a new rpc client, need give valid server address, username and password
func NewCustomerRpcClient(addr, username, password string) *CustomerRpcClient {
	// login and get token
	rc := CustomerRpcClient{}
	rc.addr = addr
	var err error

	// config TLS cert
	//creds, err := credentials.NewClientTLSFromFile("../../../cert/server.crt", "")
	//if err != nil {
	//panic(err)
	//}

	requestToken := &AuthToken{Token: "", MethodType: "Login"}
	rc.conn, err = grpc.Dial(
		addr,
		//grpc.WithTransportCredentials(creds),
		grpc.WithTransportCredentials(insecure.NewCredentials()),
		grpc.WithPerRPCCredentials(requestToken),
	)

	if err != nil {
		panic(err)
	}

	rc.grpcClient = pb.NewCerClient(rc.conn)

	loginReply, err := rc.grpcClient.Login(
		context.Background(),
		&pb.LoginRequest{Username: username, Password: password},
	)

	if err != nil {
		panic(err)
	}

	// login fail
	if loginReply.Code != 200 {
		panic(fmt.Sprintf("%d : %s", loginReply.Code, loginReply.Msg))
	}

	// login successfully
	// create request token
	requestToken = &AuthToken{Token: loginReply.Token, MethodType: "normal"}

	// get a new rpc connection with request token
	rc.conn.Close()
	rc.conn, err = grpc.Dial(
		addr,
		//grpc.WithTransportCredentials(creds),
		grpc.WithTransportCredentials(insecure.NewCredentials()),
		grpc.WithPerRPCCredentials(requestToken),
	)

	rc.grpcClient = pb.NewCerClient(rc.conn)

	if err != nil {
		panic(err)
	}

	return &rc
}

func (rc *CustomerRpcClient) Rob(userID string, businessID int64, goodID int64, couponID int64) (code int64, msg string) {
	req := &pb.RobRequest{
		UserId:     userID,
		BusinessId: businessID,
		GoodId:     goodID,
		CouponId:   couponID,
	}

	reply, err := rc.grpcClient.Rob(context.Background(), req)
	if err != nil {
		return 500, fmt.Sprintf("<rpcclient> Rob error: %s", err)
	}

	return reply.Code, reply.Msg
}

func (rc *CustomerRpcClient) GetTemplate(couponID int64) (reply *pb.TemplateReply, msg string, err2 error) {
	req := &pb.TemplateRequest{
		CouponId: couponID,
	}

	reply, err := rc.grpcClient.GetTemplate(context.Background(), req)
	if err != nil {
		return nil, fmt.Sprintf("<rpcclient> GetTemplate error: %s", err), err
	}

	return reply, "OK", nil
}

// AuthToken customer client端自定义认证，client获取server发来的token以后，再进行请求时使用
type AuthToken struct {
	Token      string
	MethodType string
}

func (c AuthToken) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
	return map[string]string{
		"authorization": c.Token,
		"methodtype":    c.MethodType,
	}, nil
}

func (c AuthToken) RequireTransportSecurity() bool {
	return false
}
